#ifndef __UDSF_MEMORY_ACCESS_C__
#define __UDSF_MEMORY_ACCESS_C__

#include "app.h"
#include "../udsf/udsf_spiflash.c"
#include "../udsf/udsf_crc.c"
#include "../udsf/udsf_uart.c"
#include "../udsf/udsf_cstdlike.c"
/*
*   notice:
*   UDSF 同UDF编程：不可调用cstd-lib,只可调用"sdk_ifs_udk_cfg.h"、"sys_api.h"中列出的API函数。
*   UDSF文件内函数均需使用static修饰符，且UDF中以#include "udsf_xxx.c"形式引用
*/

static void udsf_memory_load2sram( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t*buff,uint32_t len,eQSPI_FLASH_MODE mode) __attribute__((unused));
static void udsf_memory_program_sector( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode) __attribute__((unused));
static void udsf_memory_erase_and_program( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode) __attribute__((unused));
static void udsf_memory_erase_sector( uint32_t addr,uint8_t is_xip,uint8_t app_location,eQSPI_FLASH_MODE mode) __attribute__((unused));

static void udsf_memory_load2sram( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t*buff,uint32_t len,eQSPI_FLASH_MODE mode){

	// rom / xip48k内 统一 定义为内部。rom启动flash/xip大于48K定义为 外部。
	if( !is_xip && (app_location == APP_LOCATION_OUTER ) ){ // rom 启动，外部flash内udt->spiflash访问

		//udsf_uart_send_u32_base16(1,&addr,1,"[USRBOOT]:ADDR:","\n");
		udsf_spiflash_read_data(buff,addr,len,mode);
	}else{
		if( is_xip && (app_location == APP_LOCATION_OUTER) ){ // xip 启动 48K外flash增加偏移
			addr += SYSBIN_SIZE_MAX;
		}

		udsf_memcpy((uint8_t*)addr,buff,len);
	}
}

static void udsf_memory_program_sector( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode){

	if( is_xip && (app_location == APP_LOCATION_OUTER ) ){
		addr += SYSBIN_SIZE_MAX;
	}
	
	uint32_t len_align = SYS_ALIGN(len,FLASH_SECTOR_SIZE);
	
	if( len_align > FLASH_SECTOR_SIZE ){
		return;
	}
	
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	
	for( int j=0;j<FLASH_PAGE_PER_SECTOR;j++ ){
		if( len < (j+1)*FLASH_PAGE_SIZE ){
			udsf_spiflash_write_data(buff+j*FLASH_PAGE_SIZE,addr+j*FLASH_PAGE_SIZE,len-j*FLASH_PAGE_SIZE);
			break;
		}else{
			udsf_spiflash_write_data(buff+j*FLASH_PAGE_SIZE,addr+j*FLASH_PAGE_SIZE,FLASH_PAGE_SIZE);
			if( len == (j+1)*FLASH_PAGE_SIZE ){
				break;
			}
		}
	}
	
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

static void udsf_memory_erase_and_program( uint32_t addr,uint8_t is_xip,uint8_t app_location,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode){
	
	if( is_xip && (app_location == APP_LOCATION_OUTER ) ){
		addr += SYSBIN_SIZE_MAX;
	}
	
	len = SYS_ALIGN(len,FLASH_SECTOR_SIZE);
	
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	
	for( int i=0;i<len/FLASH_SECTOR_SIZE;i++ ){
		udsf_spiflash_erase_sector(addr+i*FLASH_SECTOR_SIZE);
		for( int j=0;j<FLASH_PAGE_PER_SECTOR;j++ ){
			udsf_spiflash_write_data(buff+i*FLASH_SECTOR_SIZE+j*FLASH_PAGE_SIZE,addr+i*FLASH_SECTOR_SIZE+j*FLASH_PAGE_SIZE,FLASH_PAGE_SIZE);
			if( i*FLASH_SECTOR_SIZE+(j+1)*FLASH_PAGE_SIZE >= len ){
				break;
			}
		}
	}
	
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

static void udsf_memory_erase_sector( uint32_t addr,uint8_t is_xip,uint8_t app_location,eQSPI_FLASH_MODE mode){
	if( is_xip && (app_location == APP_LOCATION_OUTER ) ){
		addr += SYSBIN_SIZE_MAX;
	}
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	
	udsf_spiflash_erase_sector(addr);
	
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

static void udsf_memory_erase_opt(uint32_t addr,uint8_t is_xip,eQSPI_FLASH_MODE mode){

	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	
	udsf_spiflash_opt_erase(addr);
	
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

static uint16_t udsf_memory_lock_opt(uint8_t reg1_mska,uint8_t reg2_mska,uint8_t reg1_mskb,uint8_t reg2_mskb,uint8_t is_xip,eQSPI_FLASH_MODE mode){
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	
	uint16_t reg_val = udsf_spiflash_opt_lock(reg1_mska,reg2_mska,reg1_mskb,reg2_mskb);
	
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
	return reg_val;
}

static void udsf_memory_program_opt( uint32_t addr,uint8_t is_xip,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode){
	
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	udsf_spiflash_opt_write(addr,buff,len);
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

static void udsf_memory_read_opt( uint8_t cmd,uint32_t addr,uint8_t is_xip,uint8_t* buff,uint32_t len,eQSPI_FLASH_MODE mode){
	if( is_xip ){
		// isr disable
		NVIC->ICER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
		udsf_qspi_set_xip_disable();
	}
	udsf_spiflash_opt_read(cmd,addr,buff,len);
	if( is_xip ){
		udsf_qspi_set_xip_enable(mode);
		// isr enable
		NVIC->ISER[0] = (1 << ((uint32_t)(USCI1_IRQn) & 0x1F));
	}
}

#endif
